﻿using System;
using System.Text.RegularExpressions;
using System.Text;
using System.IO;
using System.Collections.Generic;

namespace Bouyei.GeoCore.GeoParser
{
    public class PrjParser : BaseFileParser
    {
        public Projection PrjInfo { get; private set; }
        private string txt = string.Empty;

        public PrjParser(string prjfile)
            : base(prjfile)
        {

        }

        public Projection FromReader()
        {
            using (StreamReader reader = new StreamReader(filename,encoding))
            {
                txt = reader.ReadToEnd();
            }

            List<Item> items = StringTxtSplit(txt);
            List<Item> result = new List<Item>(items.Count);
            foreach(var item in items)
            {
                RecurseList(ref result, item);
            }
            result.AddRange(items);
            PrjInfo = new Projection()
            {
                PARAMETERS = new List<string>(2)
            };

            foreach(var item in result)
            {
                if (item.Name.Contains("GEOGCS"))
                {
                    PrjInfo.GeogCs = item.value.Split(',')[0];
                }
                else if (item.Name.Contains("PROJCS"))
                {
                    PrjInfo.ProjCs = item.value.Split(',')[0];
                }
                else if (item.Name.Contains("UNIT"))
                {
                    PrjInfo.UNIT = item.value;
                }
                else if (item.Name.Contains("PRIMEM"))
                {
                    PrjInfo.PRIMEM = item.value;
                }
                else if(item.Name.Contains("SPHEROID"))
                {
                    PrjInfo.SPHEROID = item.value;
                }
                else if (item.Name.Contains("PROJECTION"))
                {
                    PrjInfo.PROJECTION = item.value;
                }
                else if (item.Name.Contains("PARAMETER"))
                {
                    PrjInfo.PARAMETERS.Add(item.value);
                }
                else if (item.Name.Contains("DATUM"))
                {
                    PrjInfo.DATUM = item.value;
                }
            }

            return PrjInfo;
        }

        public override string ToString()
        {
            return txt;
        }

        private void RecurseList(ref List<Item> items,Item item)
        {
            if (item.value.Contains("["))
            {
                List<Item> rt = StringTxtSplit(item.value);
                items.AddRange(rt);

                foreach(var b in rt)
                {
                    RecurseList(ref items, b);
                }
            }
        }

        private List<Item> StringTxtSplit(string txt)
        {
            List<Item> results = new List<Item>();
            unsafe
            {
                fixed (char* c = txt)
                {
                    char* s = c;
                    Stack<char> symbolStack = new Stack<char>();
                    string temp = string.Empty;
                    bool isStartSymbol = false;
                    int startIndex = -1, endIndex = -1;
                    int index = 0;
                  
                    while (*s != '\0')
                    {
                        if (*s != '[' && isStartSymbol == false)
                        {
                            temp += *s;
                        }
                        else if (*s == '[' && isStartSymbol == false)
                        {
                            isStartSymbol = true;
                            startIndex = index;
                            
                           // temp = string.Empty;
                        }

                        if (*s == '[' && isStartSymbol)
                        {
                            symbolStack.Push('[');
                        }
                        if (*s == ']' && isStartSymbol)
                        {
                            if (symbolStack.Count > 0)
                                symbolStack.Pop();

                            if (symbolStack.Count == 0)
                            {
                                endIndex = index;
                            }
                        }

                        if (endIndex != -1 && isStartSymbol == true)
                        {
                            string content = txt.Substring(startIndex + 1, endIndex - startIndex - 1);
                         
                            results.Add(new Item() {
                                 Name=temp,
                                 value=content
                             });

                            if (endIndex + 1 < txt.Length)
                            {
                                startIndex = endIndex + 1;
                            }

                            temp = string.Empty;
                            startIndex = -1;
                            endIndex = -1;
                            isStartSymbol = false;
                        }

                        ++index;
                        ++s;
                    }
                }
            }

            return results;
        }

        private class Item
        {
           public string Name { get; set; }

           public string value { get; set; }
        }
    }

    public class Projection
    {
        /// <summary>
        /// 地理坐标系
        /// </summary>
        public string GeogCs { get; set; }
        /// <summary>
        /// 投影坐标系
        /// </summary>
        public string ProjCs { get; set; }
        /// <summary>
        /// 角度单位
        /// </summary>
        public string UNIT { get; set; }
        /// <summary>
        /// 中央子午线
        /// </summary>
        public string PRIMEM { get; set; }
        /// <summary>
        /// 地球椭球体
        /// </summary>
        public string SPHEROID { get; set; }
        /// <summary>
        /// 大地基准面
        /// </summary>
        public string DATUM { get; set; }
        /// <summary>
        /// 投影
        /// </summary>
        public string PROJECTION { get; set; }

        public List<string> PARAMETERS { get; set; }
    }
}
